#include "waSocket.h"
#include <errno.h>
#include <cstring>
#include <sys/types.h>
#include <sys/socket.h>
#include <signal.h>
#include <unistd.h>
#include <sys/time.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <string.h>
#include <string>
#include <stdio.h>
using namespace std;
namespace webapp {
waSocket :: waSocket( const string & ip, int port ) 
{
	m_sIP = ip;
	m_iPort = port;
	m_iFD = 0;
}

waSocket :: ~waSocket()
{
	if ( m_iFD >= 0 )
		close( m_iFD ), m_iFD = -1;
}

int waSocket :: Connect()
{
	// init
	struct sockaddr_in sin;	 
	sin.sin_family = AF_INET;
	sin.sin_port = htons( m_iPort );
	sin.sin_addr.s_addr = inet_addr( m_sIP.c_str() );
	
	// create socket
	if ( (m_iFD=socket(AF_INET,SOCK_STREAM,0)) < 0 )
		return 1;

	// connect
	if ( connect(m_iFD,(struct sockaddr*)&sin,sizeof(sin)) < 0 ) {
		close( m_iFD );
		m_iFD = -1;
		return 2;
	}

	return 0;
}

//###############################

waSocketWriter :: waSocketWriter( waSocket & socket )
{
	m_iFD = socket.FD();
}

int waSocketWriter :: Write( const char * pcBuf, unsigned int iBufLen )
{	
	return send( m_iFD, pcBuf, iBufLen, 0 );
}

//###############################
waSocketReader :: waSocketReader( waSocket & socket )
{
	m_iFD = socket.FD();
	memset( m_sReadBuf, 0, READBUFLEN );
	m_pReadPtr = NULL;
	m_iReadCount = 0;
}

waSocketReader :: waSocketReader( int iFD )
{
	m_iFD = iFD;
	memset( m_sReadBuf, 0, READBUFLEN );
	m_pReadPtr = NULL;
	m_iReadCount = 0;
}
		
int waSocketReader :: ReadLine( string &sLine )
{
	int		n=0, rc;
	char    c;
	sLine = "";
	for (n = 1; n < READBUFLEN; n++) 
	{
		if ( (rc = ReadChar(&c)) == 1) 
		{
			sLine += c;
			if (c == '\n')
				break;		/* ok */
		} 
		else if (rc == 0) 
		{
			return (n - 1);  /* EOF, n - 1 bytes were read */
		} 
		else
		{
			return -1;     /* error, errno set by read() */
		}
	}
	return n;
}
		
int waSocketReader :: ReadN( const int iWanted, string & sBuf )
{
	char pcBuf[1024]={0};
	//int nReadLen = 0;
	int nWantRead = 0;
	string sReadedBuf;

	while(true)
	{			
		if (iWanted> 0)
		{		
			nWantRead = iWanted - sReadedBuf.size();		
			nWantRead = (iWanted < sizeof(pcBuf)) ? nWantRead : sizeof(pcBuf);
		}
		else
		{
			nWantRead = sizeof(pcBuf);
		}

		if (nWantRead == 0)
		{
			//printf(" reach len\n");
			break;
		}

		int ret = Readn(pcBuf, nWantRead);
		if (ret < 0 )
		{
			// error
			break;
		}

		if (ret == 0)
		{
			// eof
			break;
		}
		
		sReadedBuf += string(pcBuf, ret );		
	}	
	sBuf = sReadedBuf;
	return sBuf.size();
}

int waSocketReader::Readn(char *pBuf, int iMaxLen)
{
	if (m_iReadCount <= 0)
	{
		// read
		m_iReadCount = ReadSocket();
		m_pReadPtr = m_sReadBuf;

		if (m_iReadCount <= 0)
		{
			return m_iReadCount;
		}
	}

	if (m_iReadCount <= iMaxLen)
	{
		int iRet = m_iReadCount;
		memcpy(pBuf, m_pReadPtr, m_iReadCount);
		m_iReadCount = 0;		
		return iRet;
	}
	else
	{
		memcpy(pBuf, m_pReadPtr, iMaxLen);
		m_iReadCount -= iMaxLen;	
		m_pReadPtr += iMaxLen;

		return iMaxLen;
	}
}
		
int waSocketReader :: ReadChar(char *ptr)
{
	if (m_iReadCount <= 0)
	{
		// read
		m_iReadCount = ReadSocket();
		m_pReadPtr = m_sReadBuf;
		
		printf("%s read size %d realsize %zd content:\n%s\n", __func__, m_iReadCount, strlen(m_pReadPtr), m_sReadBuf );
		
		if ( m_iReadCount <= 0 )
			return m_iReadCount;
	}

	m_iReadCount --;
	*ptr = *m_pReadPtr++;
	return 1;
}

int waSocketReader :: ReadnWait( char *pBuf, int iLen)
{
	int iLeft = iLen;
	char *ptr = pBuf;
	int iRead = 0;

	while(iLeft > 0)
	{
		iRead = Readn( ptr, iLeft);

		if (iRead <= 0)
		{
			break;
		}

		iLeft -= iRead;
		ptr += iRead;
	}

	return (iLen - iLeft);
}
		
int waSocketReader :: ReadSocket()
{
	int iReadCnt = 0;
again:
	if ( (iReadCnt = ::read(m_iFD, m_sReadBuf, READBUFLEN )) < 0) 
	{
		if (errno == EINTR)
			goto again;

		return -1;
	} 
	else if (iReadCnt == 0)
	{
		return 0;
	}

	return iReadCnt;
}
}
